#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>

#define N 41
#define M 201
int in = 0;
int out = 0; 
char buff[M]= {0}; 
sem_t empty_sem; 
sem_t full_sem;
pthread_mutex_t mutex; 
int product_id = 0;
int prochase_id = 0; 

void print()
{
    int i;
    for(i = 0; i < M; i++)
        printf ("%c ", buff[i] );
    printf( "\n" ) ;
}

void *product(void* args)
{
    int id =++product_id;
    while(1)
    {
        sleep( 1);
        char data;
        data=rand()%26+65;
        sem_wait(&empty_sem);
        pthread_mutex_lock(&mutex);
        in = in % M;
        printf("生产者%d在%2d位置生产数据%c:", id, in,data);
        buff[in] = data;
        print();
        ++in;
        pthread_mutex_unlock(&mutex);
        sem_post(&full_sem) ;
    }

    return NULL;
}


void *prochase(void* args)
{
    char data;
    int id =++prochase_id;
    while(1)
    {
        sleep(5);
        sem_wait(&full_sem) ;
        pthread_mutex_lock ( &mutex);
        out = out % M;
        data=buff[out];
        printf("消费者%d在%2d位西消费数据%c: ", id, out,data);
        buff[out] ='*';
        print( );
        ++out;
        pthread_mutex_unlock ( &mutex );
        sem_post(&empty_sem) ;
    }
}

int main()
{
    pthread_t id1[N];
    pthread_t id2[N];
    int i;
    int ret[N];

    int ini1 = sem_init(&empty_sem, 0,M);
    int ini2 = sem_init(&full_sem, 0, 0);
    if(ini1 && ini2 != 0)
    {
        printf("初始化同步信号量失败\n");
        exit( 1);
    }
    int ini3 = pthread_mutex_init ( &mutex, NULL);
    if(ini3 != 0)
    {
        printf("初始化互斥信号量失败\n");
        exit( 1);
    }

    for(i = 0; i < N; i++)
    {
        ret[i] = pthread_create(&id1[i], NULL, product, (void *)(&i));
        if (ret[i]!= 0)
        {
            printf("生产者%d创建失败\n", i);
            exit(1);
        }
    }
    
    for(i =0; i < N;i++)
    {
        ret[i] = pthread_create(&id2[1], NULL, prochase, NULL);
        if( ret[i]!= 0)
        {
            printf("消费者%d创建失败\n", i);
            exit(1);
        }
    }
    
    for(i = 0; i < N; i++)
    {
        pthread_join(id1[i], NULL);
        pthread_join(id2[i], NULL);
    }

    exit(0);
}
